home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / wb / czesc_3 / reyes / main.c < prev    next >
C/C++ Source or Header  |  1997-12-31  |  31KB  |  1,198 lines

  1. /*
  2.  * REyes 
  3.  *
  4.  * A screen blanker for the Retina graphics card.
  5.  * By Michael Heinz, 8 January, 1994
  6.  *
  7.  * Main routines
  8.  *
  9.  */
  10.  
  11. #include <exec/memory.h>
  12. #include <exec/ports.h>
  13. #include <exec/execbase.h>
  14. #include <graphics/displayinfo.h>
  15. #include <intuition/intuitionbase.h>
  16. #include <intuition/gadgetclass.h>
  17. #include <libraries/commodities.h>
  18. #include <libraries/gadtools.h>
  19. #include <dos/dosextens.h>
  20. #include <dos/dostags.h>
  21. #include <utility/tagitem.h>
  22.  
  23. #include <clib/alib_protos.h>
  24. #include <clib/commodities_protos.h>
  25. #include <clib/dos_protos.h>
  26. #include <clib/exec_protos.h>
  27. #include <clib/gadtools_protos.h>
  28. #include <clib/graphics_protos.h>
  29. #include <clib/intuition_protos.h>
  30. #include <clib/macros.h>
  31. #include <clib/retina_protos.h>
  32. #include <retina/retina.h>
  33.  
  34. #include <string.h>
  35. #include <stdlib.h>
  36.  
  37. #include <pragmas/commodities_pragmas.h>
  38. #include <pragmas/dos_pragmas.h>
  39. #include <pragmas/exec_pragmas.h>
  40. #include <pragmas/gadtools_pragmas.h>
  41. #include <pragmas/graphics_pragmas.h>
  42. #include <pragmas/intuition_pragmas.h>
  43. #include <pragmas/retina_pragmas.h>
  44.  
  45. #ifdef SMALLEYES
  46. #include "smalleyes.h"
  47. #else
  48. #include "retinaeyes.h"
  49. #endif
  50.  
  51. UBYTE *VersionString = "$VER: REyes 1.2 (By Michael Heinz)";
  52.  
  53. #define NORMAL_WIDE 640
  54. #define NORMAL_HIGH 480
  55. #define SMALL_WIDE 320
  56. #define SMALL_HIGH 240
  57.  
  58. void
  59. chkabort(void)
  60. {
  61. }
  62.  
  63. /*
  64.  * Common Definitions
  65.  */
  66.  
  67. extern struct ExecBase *SysBase;
  68. extern struct DosLibrary *DOSBase;
  69. struct IntuitionBase *IntuitionBase;
  70. struct RetinaBase *RetinaBase;
  71. struct Library *CxBase, *GadToolsBase, *IconBase;
  72.  
  73. #define FINDPROCPORT (&((struct Process *)SysBase->ThisTask)->pr_MsgPort)
  74.  
  75.  
  76. /*
  77.  * A handy request structure for reporting that we've up and died.
  78.  */
  79. struct EasyStruct quitreq =
  80. {
  81.     sizeof(struct EasyStruct),
  82.     0,
  83.     "REyes",
  84.     "REyes has suffered an untimely demise\ndue to: %s",
  85.     "OK|OK"
  86. };
  87.  
  88. void 
  89. Error(char *s)
  90. {
  91.     if (s) EasyRequest(NULL,&quitreq,NULL,s);
  92. }
  93.  
  94. /*
  95.  * Definitions for our Commodity
  96.  */
  97. struct NewBroker NewBroker =
  98. {NB_VERSION, "REyes ", "Retina Blanker V1.2",
  99.  "Somebody's watching you...", NBU_NOTIFY | NBU_UNIQUE, COF_SHOW_HIDE,
  100.  0, NULL, 0};
  101.  
  102. struct MsgPort *CxPort;
  103.  
  104. UBYTE *PopKey;
  105. UBYTE *BlankKey;
  106.  
  107. #define HOTKEY_OPEN_WINDOW 1L
  108. #define HOTKEY_BLANK_SCREEN 2L
  109.  
  110. #define DEF_CX_PRI 0
  111. #define DEF_POPKEY "control alt s"
  112. #define DEF_BLANKKEY "lamiga s"
  113.  
  114. LONG TimeOut, ClientTimeOut;
  115.  
  116. #define MAX_TIMEOUT        3600L
  117. #define MAX_CLIENT_TIMEOUT 60L
  118.  
  119. #define DEF_TIMEOUT        60L
  120. #define DEF_CLIENT_TIMEOUT 5L
  121.  
  122. #define SERVER_PRI 3L
  123. #define CLIENT_PRI -5L
  124.  
  125. /*
  126.  * Definitions for Eye Movement
  127.  */
  128. #define RAND(m) (Random(m)-(m)/2)
  129.  
  130. #define MAX_SPEED     10L
  131. #define MAX_EYES      10L
  132. #define MAX_CHANCE      100L
  133.  
  134. #define DEF_EYES      5L
  135. #define DEF_SPEED     4L
  136. #define DEF_CHANCE      10L
  137.  
  138. #define DEF_MODE MID_DEFAULT_08
  139.  
  140. LONG NumEyes, Speed, Chance;
  141.  
  142. typedef struct {
  143.     int NumEyes;
  144.     Eyes *Eye[MAX_EYES];
  145. } EyeStruct;
  146.  
  147.  
  148. EyeStruct EyeList;
  149.  
  150. /*
  151.  * Definitions for our configuration window
  152.  */
  153.  
  154. struct NewWindow NewBlankerWindow =
  155. {
  156.     80, 16, 0, 0, 0, 1,
  157.     IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | IDCMP_GADGETDOWN |
  158.     IDCMP_GADGETUP | IDCMP_VANILLAKEY | SLIDERIDCMP | LISTVIEWIDCMP,
  159.     WINDOWCLOSE | WINDOWDRAG | WINDOWDEPTH | SIMPLE_REFRESH,
  160.     NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0,
  161.     WBENCHSCREEN
  162. };
  163.  
  164. struct Window *BlankerWindow;
  165.  
  166. #define GID_HIDE          1
  167. #define GID_BLANK         2
  168. #define GID_QUIT          3
  169. #define GID_TIMEOUT       4
  170. #define GID_CLIENT        5
  171. #define GID_EYES          6
  172. #define GID_SPEED         7
  173. #define GID_CHANCE          8
  174.  
  175. #ifdef SMALLEYES
  176. #define NUM_GADS         7
  177. #else
  178. #define NUM_GADS         8
  179. #endif
  180.  
  181. struct VisualInfo *BlankerVisualInfo;
  182. struct Gadgets *BlankerGadgets;
  183. struct TextAttr BlankerAttr =
  184. {"topaz.font", TOPAZ_EIGHTY, FS_NORMAL, FPF_ROMFONT};
  185.  
  186. struct NewGadget NewBlankerGadgets[NUM_GADS] =
  187. {16, 101, 48, 12, "_Hide", &BlankerAttr, GID_HIDE, PLACETEXT_IN, NULL, NULL,
  188.  80, 101, 48, 12, "_Blank", &BlankerAttr, GID_BLANK, PLACETEXT_IN, NULL, NULL,
  189.  144, 101, 48, 12, "_Quit", &BlankerAttr, GID_QUIT, PLACETEXT_IN, NULL, NULL,
  190.  136, 5, 66, 12, "Timeout", &BlankerAttr, GID_TIMEOUT, PLACETEXT_LEFT, NULL, NULL,
  191.  136, 21, 66, 12, "Client Timeout", &BlankerAttr, GID_CLIENT, PLACETEXT_LEFT, NULL, NULL,
  192.  136, 53, 66, 12, "Speed    ", &BlankerAttr, GID_SPEED, PLACETEXT_LEFT, NULL, NULL,
  193.  136, 69, 66, 12, "Eyes     ", &BlankerAttr, GID_EYES, PLACETEXT_LEFT, NULL, NULL,
  194. #ifndef SMALLEYES
  195.  136, 37, 66, 12, "%Anim    ", &BlankerAttr, GID_CHANCE, PLACETEXT_LEFT, NULL, NULL,
  196. #endif
  197. };
  198.  
  199. UBYTE BlankerGadgetKinds[NUM_GADS] =
  200. {
  201.     BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, INTEGER_KIND, INTEGER_KIND, SLIDER_KIND,
  202.     SLIDER_KIND, 
  203. #ifndef SMALLEYES
  204.     SLIDER_KIND
  205. #endif
  206. };
  207.  
  208. struct TagItem ButtonGadgetTags[] =
  209. {GT_Underscore, (ULONG) '_', TAG_DONE, 0L};
  210.  
  211. struct TagItem TimeGadgetTags[] =
  212. {GTIN_Number, 0L, GTIN_MaxChars, 4L, TAG_DONE, 0L};
  213.  
  214. struct TagItem ClientGadgetTags[] =
  215. {GTIN_Number, 0L, GTIN_MaxChars, 2L, TAG_DONE, 0L};
  216.  
  217. struct TagItem ChanceGadgetTags[] =
  218. {GTSL_Level, 0L, GTSL_Min, 1L, GTSL_Max, MAX_CHANCE, GTSL_LevelFormat, 0L,
  219.  GTSL_LevelPlace, PLACETEXT_LEFT, GTSL_MaxLevelLen, 3L, GA_RELVERIFY, TRUE,
  220.  TAG_DONE, 0L};
  221.  
  222. struct TagItem SpeedGadgetTags[] =
  223. {GTSL_Level, 0L, GTSL_Min, 1L, GTSL_Max, MAX_SPEED, GTSL_LevelFormat, 0L,
  224.  GTSL_LevelPlace, PLACETEXT_LEFT, GTSL_MaxLevelLen, 2L, GA_RELVERIFY, TRUE,
  225.  TAG_DONE, 0L};
  226.  
  227. struct TagItem EyesGadgetTags[] =
  228. {GTSL_Level, 0L, GTSL_Min, 1L, GTSL_Max, MAX_EYES, GTSL_LevelFormat, 0L,
  229.  GTSL_LevelPlace, PLACETEXT_LEFT, GTSL_MaxLevelLen, 2L, GA_RELVERIFY, TRUE,
  230.  TAG_DONE, 0L};
  231.  
  232. struct TagItem *BlankerGadgetTagLists[NUM_GADS] =
  233. {
  234.     &ButtonGadgetTags[0],
  235.      &ButtonGadgetTags[0],
  236.      &ButtonGadgetTags[0],
  237.      &TimeGadgetTags[0],
  238.      &ClientGadgetTags[0],
  239.      &SpeedGadgetTags[0],
  240.      &EyesGadgetTags[0],
  241. #ifndef SMALLEYES
  242.      &ChanceGadgetTags[0],
  243. #endif
  244. };
  245.  
  246. /*
  247.  * Definitions for Server/Client Communication
  248.  */
  249.  
  250. BYTE bsp_TimerSig, bsp_InputSig, bsp_ClientSig;
  251. struct Task *BlankerServerProcess;
  252.  
  253. #define MASK(n) (1L<<(n))
  254.  
  255. struct ClientMessage {
  256.     struct Message bcm_Message;
  257.     struct RetinaScreen *bcm_Screen;
  258.     LONG bcm_Status;
  259.     ULONG bcm_SigMask;
  260.     LONG bcm_Eyes, bcm_Speed, bcm_Chance;
  261. };
  262.  
  263. /*
  264.  * The following functions are used to track resources.
  265.  */
  266. struct ToolNode {
  267.     struct ToolNode *Next;
  268.     void *Tool;
  269.     void (*RemProc) (void *, LONG);
  270.     LONG Size;
  271. }
  272.  
  273. *ToolList;
  274.  
  275. void __regargs
  276. RemTool(void *Tool)
  277. {
  278.     struct ToolNode **Ptr, *ToolNode;
  279.  
  280.     Ptr = &ToolList;
  281.     while (*Ptr)
  282.         if ((*Ptr)->Tool == Tool) {
  283.             ToolNode = *Ptr;
  284.             *Ptr = (*Ptr)->Next;
  285.             ToolNode->RemProc(ToolNode->Tool, ToolNode->Size);
  286.             FreeMem(ToolNode, sizeof(struct ToolNode));
  287.         } else
  288.             Ptr = &(*Ptr)->Next;
  289. }
  290.  
  291. void __regargs
  292. Quit(int ReturnCode, char *s)
  293. {
  294.     while (ToolList)
  295.         RemTool(ToolList->Tool);
  296.     if (ReturnCode) Error(s);
  297.     exit(ReturnCode);
  298. }
  299.  
  300. void __regargs
  301. AddTool(void *NewTool, void *ProcPtr, LONG NewSize, char *errmsg)
  302. {
  303.     struct ToolNode *Ptr;
  304.     void (*NewRemProc) (void *, LONG);
  305.  
  306.     NewRemProc = ProcPtr;
  307.     if (NewTool == NULL)
  308.         Quit(10,errmsg);
  309.  
  310.     if ((Ptr = AllocMem(sizeof(struct ToolNode), MEMF_CLEAR)) == NULL) {
  311.         NewRemProc(NewTool, NewSize);
  312.         Quit(20,"Out of Memory.");
  313.     }
  314.     Ptr->Next = ToolList;
  315.     Ptr->Tool = NewTool;
  316.     Ptr->RemProc = NewRemProc;
  317.     Ptr->Size = NewSize;
  318.     ToolList = Ptr;
  319. }
  320.  
  321. /*
  322.  * Some utility functions
  323.  */
  324.  
  325. void __stdargs
  326. DeleteMsgPortSafely(struct MsgPort *AnyPort)
  327. {
  328.     struct Message *AnyMsg;
  329.  
  330.     while (AnyMsg = GetMsg(AnyPort))
  331.         ReplyMsg(AnyMsg);
  332.     DeleteMsgPort(AnyPort);
  333. }
  334.  
  335. int __regargs
  336. ArgIntMax(char **ToolTypes, char *ID, int Default, int Max)
  337. {
  338.     int Val;
  339.  
  340.     Val = ArgInt(ToolTypes, ID, Default);
  341.     if ((Val < 1) || (Val > Max))
  342.         return Default;
  343.     else
  344.         return Val;
  345. }
  346.  
  347. /*
  348.  * The "InputHandler".  It signals the server process
  349.  * when an input or timer event is received.
  350.  */
  351.  
  352. void __interrupt __saveds
  353. BlankerAction(CxMsg * CxMsg, CxObj * CO)
  354. {
  355.     struct InputEvent *IE;
  356.  
  357.     IE = (struct InputEvent *)CxMsgData(CxMsg);
  358.     if (IE->ie_Class == IECLASS_TIMER)
  359.         Signal(BlankerServerProcess, 1L << bsp_TimerSig);
  360.     else
  361.         Signal(BlankerServerProcess, 1L << bsp_InputSig);
  362. }
  363.  
  364. /*
  365.  * Functions for Handling the Configuration Window
  366.  */
  367.  
  368. LONG
  369. GetNum(struct Gadget *Gadget, LONG * Data, LONG Max)
  370. {
  371.     LONG NewData;
  372.  
  373.     NewData = ((struct StringInfo *)Gadget->SpecialInfo)->LongInt;
  374.     if ((NewData < 1L) || (NewData > Max)) {
  375.         GT_SetGadgetAttrs(Gadget, BlankerWindow, NULL, GTIN_Number, (ULONG) * Data, 
  376.                           TAG_DONE);
  377.         return FALSE;
  378.     } else {
  379.         *Data = NewData;
  380.         return TRUE;
  381.     }
  382. }
  383.  
  384. void
  385. CloseBlankerWindow(void)
  386. {
  387.     if (BlankerWindow) {
  388.         /* 
  389.          * We save the current position of the window
  390.          * so it will re-open in the same place, later.
  391.          */
  392.         NewBlankerWindow.LeftEdge = BlankerWindow->LeftEdge;
  393.         NewBlankerWindow.TopEdge = BlankerWindow->TopEdge;
  394.  
  395.         RemTool(BlankerGadgets);
  396.         RemTool(BlankerVisualInfo);
  397.         RemTool(BlankerWindow);
  398.         BlankerWindow = NULL;
  399.     }
  400. }
  401.  
  402. void
  403. OpenBlankerWindow(void)
  404. {
  405.     struct Gadget *Ptr;
  406.     UWORD Index;
  407.     static char Title[80];
  408.  
  409.     if (BlankerWindow == NULL) {
  410.         strcpy(Title, "REyes = <");
  411.         strcat(Title, PopKey);
  412.         strcat(Title, ">");
  413.  
  414.         if (BlankerWindow = OpenWindowTags(&NewBlankerWindow, WA_Title, Title,
  415.                                                WA_AutoAdjust, TRUE, WA_InnerWidth, 
  416.                                             212, WA_InnerHeight, 118, TAG_DONE)) {
  417.                                
  418.             AddTool(BlankerWindow, CloseWindow, NULL,"Could not open the window.");
  419.  
  420.             if ((BlankerVisualInfo = GetVisualInfo(BlankerWindow->WScreen, TAG_DONE)) 
  421.                 == NULL) {
  422.                 RemTool(BlankerWindow);
  423.                 return;
  424.             }
  425.             AddTool(BlankerVisualInfo, FreeVisualInfo, 0L, 
  426.                     "Couldn't get visual data.");
  427.  
  428.             BlankerGadgets = NULL;
  429.             if ((Ptr = CreateContext(&BlankerGadgets)) == NULL) {
  430.                 RemTool(BlankerVisualInfo);
  431.                 RemTool(BlankerWindow);
  432.                 return;
  433.             }
  434.             AddTool(Ptr, FreeGadgets, 0L,"Couldn't allocate the gadgets.");
  435.  
  436.             /* Here we re-load the gadgets with the current settings. */
  437.             TimeGadgetTags[0].ti_Data = (ULONG) TimeOut;
  438.             ClientGadgetTags[0].ti_Data = (ULONG) ClientTimeOut;
  439.             SpeedGadgetTags[0].ti_Data = (ULONG) Speed;
  440.             SpeedGadgetTags[3].ti_Data = (ULONG) "%2ld";
  441. #ifndef SMALLEYES
  442.             ChanceGadgetTags[0].ti_Data = (ULONG) Chance;
  443.             ChanceGadgetTags[3].ti_Data = (ULONG) "%3ld";
  444. #endif
  445.             EyesGadgetTags[0].ti_Data = (ULONG) NumEyes;
  446.             EyesGadgetTags[3].ti_Data = (ULONG) "%2ld";
  447.  
  448.             for (Index = 0L; Index < NUM_GADS; Index++) {
  449.                 NewBlankerGadgets[Index].ng_TopEdge += BlankerWindow->BorderTop;
  450.  
  451.                 NewBlankerGadgets[Index].ng_VisualInfo = BlankerVisualInfo;
  452.                 Ptr = CreateGadgetA((ULONG) BlankerGadgetKinds[Index], Ptr,
  453.                                     &NewBlankerGadgets[Index], 
  454.                                     BlankerGadgetTagLists[Index]);
  455.                 if (Ptr == NULL) {
  456.                     CloseBlankerWindow();
  457.                     return;
  458.                 }
  459.                 NewBlankerGadgets[Index].ng_TopEdge -= BlankerWindow->BorderTop;
  460.             }
  461.  
  462.             AddGList(BlankerWindow, BlankerGadgets, 0L, -1L, NULL);
  463.             RefreshGadgets(BlankerGadgets, BlankerWindow, NULL);
  464.             GT_RefreshWindow(BlankerWindow, NULL);
  465.         }
  466.     }
  467.     ScreenToFront(BlankerWindow->WScreen);
  468.     WindowToFront(BlankerWindow);
  469.     ActivateWindow(BlankerWindow);
  470. }
  471.  
  472. /*
  473.  * Function to handle the Commodity Stuff
  474.  */
  475.  
  476. void __regargs
  477. HandleCxMsg(CxObj * Broker, CxMsg * CxMsg, LONG * TimeUntilBlank,
  478.             LONG * ThisTimeOut)
  479. {
  480.     ULONG MsgType, MsgID;
  481.  
  482.     MsgType = CxMsgType(CxMsg);
  483.     MsgID = CxMsgID(CxMsg);
  484.     ReplyMsg((struct Message *)CxMsg);
  485.  
  486.     switch (MsgType) {
  487.         case CXM_IEVENT:        /* a hotkey was pressed */
  488.             switch (MsgID) {
  489.                 case HOTKEY_OPEN_WINDOW:
  490.                     OpenBlankerWindow();
  491.                     break;
  492.                 case HOTKEY_BLANK_SCREEN:
  493.                     if (*TimeUntilBlank)
  494.                         *TimeUntilBlank = *ThisTimeOut = 2L;
  495.             }
  496.         case CXM_COMMAND:
  497.             switch (MsgID) {
  498.                 case CXCMD_DISABLE:    /* Message from Exchange
  499.                                          * (except CXCMD_UNIQUE) */
  500.                     (void)ActivateCxObj(Broker, FALSE);
  501.                     break;
  502.                 case CXCMD_ENABLE:
  503.                     (void)ActivateCxObj(Broker, TRUE);
  504.                     break;
  505.                 case CXCMD_UNIQUE:
  506.                 case CXCMD_APPEAR:
  507.                     OpenBlankerWindow();
  508.                     break;
  509.                 case CXCMD_DISAPPEAR:
  510.                     CloseBlankerWindow();
  511.                     break;
  512.                 case CXCMD_KILL:
  513.                     Quit(0,"Normal Termination.");
  514.             }
  515.     }
  516. }
  517.  
  518. #ifdef OBSOLETE
  519. /*
  520.  * These functions have been replaced by defines.
  521.  * They're provided here for hysterical raisins.
  522.  */
  523. void
  524. SpritesOff(struct RetinaScreen *rs)
  525. {
  526.     struct TagItem tags[] =
  527.     {RSP_On, 0L, TAG_DONE, 0L};
  528.  
  529.     Retina_SpriteFunction(rs, tags);
  530. }
  531.  
  532. void
  533. SpritesOn(struct RetinaScreen *rs)
  534. {
  535.     struct TagItem tags[] =
  536.     {RSP_On, 1L, TAG_DONE, 0L};
  537.  
  538.     Retina_SpriteFunction(rs, tags);
  539. }
  540. #else
  541. /*
  542.  * We use defines for these functions just to pick up a little speed.
  543.  */
  544.  
  545. #define SpritesOff(rs)                 \
  546. {                                    \
  547.     struct TagItem tags[] =            \
  548.     {RSP_On, 0L, TAG_DONE, 0L};        \
  549.                                     \
  550.     Retina_SpriteFunction(rs, tags);\
  551. }
  552.     
  553. #define SpritesOn(rs)                \
  554. {                                    \
  555.     struct TagItem tags[] =            \
  556.     {RSP_On, 1L, TAG_DONE, 0L};        \
  557.                                     \
  558.     Retina_SpriteFunction(rs, tags);\
  559. }
  560. #endif
  561.  
  562. /*
  563.  * This, annoyingly enough, is neccessary because Retina_CloseScreen is
  564.  * actually a #pragma and not a real function call.  This means you
  565.  * can't pass a pointer to Retina_CloseScreen as a function argument
  566.  * to AddTool.  By adding this wrapper function, we make AddTool work.
  567.  */
  568. void
  569. DestroyScreen(struct RetinaScreen *rs)
  570. {
  571.     Retina_CloseScreen(rs);
  572. }
  573.  
  574. /*
  575.  * Create Screen will first attempt to open a "normal" resolution screen.
  576.  * If that fails, it will try opening a lower resolution screen.
  577.  * If that fails it will return NULL.
  578.  */
  579. struct RetinaScreen *
  580. CreateScreen(void)
  581. {
  582.     struct RetinaScreen *Screen;
  583.  
  584.     if (!(Screen = Retina_OpenScreen(NORMAL_WIDE, NORMAL_HIGH, MID_DEFAULT_08, 
  585.                                      RSFF_DOUBLEBUFFER, NULL))) 
  586.         if (!(Screen = Retina_OpenScreen(SMALL_WIDE, SMALL_HIGH, MID_DEFAULT_08, 
  587.                                          RSFF_DOUBLEBUFFER, NULL))) 
  588.             return NULL;
  589.     
  590.     Retina_LoadPalette(Screen, 0, EYES_COLS, color_table);
  591.     SpritesOff(Screen);
  592.     return Screen;
  593. }
  594.  
  595. /*
  596.  * Functions for Creating/Deleting the Client Process
  597.  */
  598.  
  599. void __stdargs
  600. DeleteBlankerClient(struct MsgPort * ClientPort)
  601. {
  602.     struct ClientMessage ClientMessage;
  603.  
  604.     /* Send the terminating message to the client. 
  605.      * We kick up the client's priority to ensure a 
  606.      * prompt response.
  607.      */
  608.     Forbid();
  609.     ClientMessage.bcm_Message.mn_ReplyPort = FINDPROCPORT;
  610.     PutMsg(ClientPort, (struct Message *)&ClientMessage);
  611.     
  612.     (void)SetTaskPri(ClientPort->mp_SigTask, SERVER_PRI);
  613.     Permit();
  614.     
  615.     /* Get the response. */
  616.     (void)WaitPort(ClientMessage.bcm_Message.mn_ReplyPort);
  617.     (void)GetMsg(ClientMessage.bcm_Message.mn_ReplyPort);
  618. }
  619.  
  620. struct MsgPort *__regargs
  621. CreateBlankerClient(void *ClientRoutine, struct ClientMessage *ClientMessage)
  622. {
  623.     struct Process *ClientProcess;
  624.     struct TagItem ProcTags[3];
  625.  
  626.     ProcTags[0].ti_Tag = NP_Entry;
  627.     ProcTags[0].ti_Data = (ULONG) ClientRoutine;
  628.     ProcTags[1].ti_Tag = NP_Name;
  629.     ProcTags[1].ti_Data = (ULONG) "ClientProcess";
  630.     ProcTags[2].ti_Tag = TAG_DONE;
  631.  
  632.     if (ClientProcess = CreateNewProc(ProcTags)) {
  633.         ClientMessage->bcm_Message.mn_ReplyPort = FINDPROCPORT;
  634.         PutMsg(&ClientProcess->pr_MsgPort, (struct Message *)ClientMessage);
  635.  
  636.         (void)WaitPort(ClientMessage->bcm_Message.mn_ReplyPort);
  637.         (void)GetMsg(ClientMessage->bcm_Message.mn_ReplyPort);
  638.  
  639.         (void)SetTaskPri((struct Task *)ClientProcess, CLIENT_PRI);
  640.  
  641.         if (ClientMessage->bcm_Status)
  642.             return &ClientProcess->pr_MsgPort;
  643.     }
  644.     return NULL;
  645. }
  646.  
  647. /*
  648.  * Functions for Creating/Drawing/Removing the Eyes
  649.  */
  650.  
  651. LONG __inline
  652. Insure1(LONG val)
  653. {
  654.     return ((val == 0) ? 1 : val);    /* return value that is at least 1 */
  655. }
  656.  
  657. /* 
  658.  * This is a fairly high-speed psuedo random number generator,
  659.  * but it's not to random, though.  Occasionally, it will
  660.  * be non-random enough for a while to cause all the Eyes to
  661.  * move in the same direction (or some such.)  I use it
  662.  * because it's fast and because, with all the collision 
  663.  * detection done now, it's less likely the un-randomness
  664.  * will be noticed.
  665.  */
  666. WORD __regargs
  667. Random(WORD Max)
  668. {
  669.     static ULONG Num = 0L;
  670.     ULONG Sec, Mic;
  671.  
  672.     CurrentTime((LONG *) & Sec, (LONG *) & Mic);
  673.  
  674.     Num *= Sec;
  675.     Num += Mic;
  676.  
  677.     while (Num > 32767L)
  678.         Num = Num >> 1;
  679.  
  680.     return (WORD) Num % Max;
  681. }
  682.  
  683. /*
  684.  * Free up the list of eyes.
  685.  */
  686. void __regargs
  687. DeleteEyes(EyeStruct *EyeList)
  688. {
  689.     LONG i;
  690.  
  691.     for (i=0;i<EyeList->NumEyes;i++) 
  692.         if (EyeList->Eye[i]!=NULL) FreeMem(EyeList->Eye[i],sizeof(Eyes));
  693. }
  694.  
  695. /*
  696.  * Create the list of eyes.
  697.  */
  698. EyeStruct *__regargs
  699. CreateEyes(struct RetinaScreen *Screen,
  700.             LONG NumEyes, LONG Speed)
  701. {
  702.     int Index, i, flag, count;
  703.     Eyes *randomeyes[4];
  704.     
  705.     if (!Screen) return NULL;
  706.     
  707.     randomeyes[0]=&BlueEyes;
  708.     randomeyes[1]=&GreenEyes;
  709.     randomeyes[2]=&VioletEyes;
  710.     randomeyes[3]=&BrownEyes;
  711.  
  712.     /*
  713.      * Create the Eyes
  714.      */
  715.     for (Index = 0; Index < NumEyes; Index++) {
  716.         if (!(EyeList.Eye[Index]=AllocMem(sizeof(Eyes),MEMF_PUBLIC|MEMF_CLEAR))) 
  717.             Quit(20,"Out of Memory!!!");
  718.         CopyMem(randomeyes[Random(4)],EyeList.Eye[Index],sizeof(Eyes));
  719. #ifndef SMALLEYES
  720.         EyeList.Eye[Index]->currentframe=Random(EyeList.Eye[Index]->maxframes);
  721. #else
  722.         EyeList.Eye[Index]->currentframe=0;
  723. #endif
  724.            EyeList.Eye[Index]->xspeed=Insure1(RAND(Speed));
  725.            EyeList.Eye[Index]->yspeed=Insure1(RAND(Speed));
  726.         count=0; flag=1;
  727.  
  728.         /* 
  729.          * We try 4 times to fit an eye pair on the screen.  If we can't, then
  730.          * the screen must be too small for the # of eyes and we truncate the list.
  731.          */
  732.         while (flag & count<4) {
  733.             EyeList.Eye[Index]->xpos=Random(Screen->rs_Width-
  734.                                             EyeList.Eye[Index]->width);
  735.             EyeList.Eye[Index]->ypos=Random(Screen->rs_Height-
  736.                                             EyeList.Eye[Index]->height);
  737.             flag=0;
  738.             for (i=0;i<Index; i++) {
  739.                 /* Looking for overlapping rectangles... */
  740.                 if ((EyeList.Eye[i]->xpos>
  741.                      EyeList.Eye[Index]->xpos-EyeList.Eye[i]->width)&&
  742.                     (EyeList.Eye[i]->xpos<
  743.                      EyeList.Eye[Index]->xpos+EyeList.Eye[Index]->width)&&
  744.                     (EyeList.Eye[i]->ypos>
  745.                      EyeList.Eye[Index]->ypos-EyeList.Eye[i]->height)&&
  746.                     (EyeList.Eye[i]->ypos<
  747.                      EyeList.Eye[Index]->ypos+EyeList.Eye[Index]->height)) {
  748.                     flag=1;
  749.                     break;
  750.                 }
  751.             }
  752.         }
  753.         if (flag) {    /* If we failed to add an Eye pair, truncate the list. */
  754.             NumEyes=Index+1;
  755.             break;
  756.         }
  757.     }
  758.  
  759.     EyeList.NumEyes=NumEyes;
  760.     
  761.     return &EyeList;
  762. }
  763.  
  764. /* move the Eyes and redraw them */
  765.  
  766. void __regargs
  767. DrawEyes(EyeStruct *EyeList, struct RetinaScreen *rs, LONG Chance)
  768. {
  769.     int Index,i;
  770.     Eyes **EL;
  771.  
  772.     /* 
  773.      * This assignment provides a (very mild) speed up buy removing
  774.      * one level of indirection from all the work that's going on below.
  775.      */
  776.     EL=EyeList->Eye;
  777.  
  778.     Chance=Insure1(100-Chance);
  779.  
  780.     /* If we don't have a screen, don't draw on it! (duh.) */
  781.     if (!rs) return; 
  782.  
  783.     for (Index=0; Index<EyeList->NumEyes; Index++) {
  784.         /* Move the Eye. */
  785.         EL[Index]->old_xpos=EL[Index]->xpos;
  786.         EL[Index]->old_ypos=EL[Index]->ypos;
  787.         EL[Index]->xpos+=EL[Index]->xspeed;
  788.         EL[Index]->ypos+=EL[Index]->yspeed;
  789.         
  790.         /* Bounce check */
  791.         if (EL[Index]->xpos<0) { 
  792.             EL[Index]->xpos=0; 
  793.             EL[Index]->xspeed=Insure1(RAND(Speed));
  794.         } else if (EL[Index]->xpos>rs->rs_Width-EL[Index]->width-1) {
  795.             EL[Index]->xpos=rs->rs_Width-EL[Index]->width-1;
  796.             EL[Index]->xspeed=Insure1(RAND(Speed));
  797.         }
  798.         if (EL[Index]->ypos<0) { 
  799.             EL[Index]->ypos=0; 
  800.             EL[Index]->yspeed=Insure1(RAND(Speed));
  801.         } else if (EL[Index]->ypos>rs->rs_Height-EL[Index]->height-1) {
  802.             EL[Index]->ypos=rs->rs_Height-EL[Index]->height-1;
  803.             EL[Index]->yspeed=Insure1(RAND(Speed));
  804.         }
  805.  
  806.         /* 
  807.          * Collision check... 
  808.          * If we detect that we hit one other eye pair, we reverse direction.
  809.          * Note - checking stops after the first collision, otherwise
  810.          * multiple-collisions might cause the eye pair to continue in
  811.          * the same direction (i.e., its direction got negated twice)
  812.          */
  813.         for (i=0;i<EyeList->NumEyes; i++) {
  814.             if (i!=Index) {
  815.                 if ((EL[i]->xpos>EL[Index]->xpos-EL[i]->width)&&
  816.                     (EL[i]->xpos<EL[Index]->xpos+EL[Index]->width)&&
  817.                     (EL[i]->ypos>EL[Index]->ypos-EL[i]->height)&&
  818.                     (EL[i]->ypos<EL[Index]->ypos+EL[Index]->height)) {
  819.  
  820.                     EL[Index]->yspeed= (EL[Index]->yspeed>0)?-Insure1(Random(Speed/2)):Insure1(Random(Speed/2));
  821.                     EL[Index]->xspeed= (EL[Index]->xspeed>0)?-Insure1(Random(Speed/2)):Insure1(Random(Speed/2));
  822.                     EL[Index]->xpos=EL[Index]->old_xpos;
  823.                     EL[Index]->ypos=EL[Index]->old_ypos;
  824.                     break;
  825.                 }
  826.             }
  827.         }
  828. #ifndef SMALLEYES
  829.         /* Are we animating this Eye pair? */
  830.         if (EL[Index]->currentframe) {
  831.             if (!EL[Index]->tic) {
  832.                 EL[Index]->tic++;
  833.             } else {
  834.                 EL[Index]->tic=0;
  835.                 EL[Index]->currentframe=(EL[Index]->currentframe+1)%
  836.                                     EL[Index]->maxframes;
  837.             }
  838.         /* No?  Then roll the dice and see if we should start... */
  839.         } else if (!Random(Chance)) { 
  840.             EL[Index]->currentframe=1;
  841.         }
  842. #endif
  843.             
  844.     }
  845.  
  846.     /* Redraw on the background bitmap... */
  847.     for (Index=0; Index<EyeList->NumEyes; Index++) {
  848.         Retina_WriteRect(EL[Index]->animtable[EL[Index]->currentframe],
  849.                          0,0,
  850.                          EL[Index]->width, RECTMODE_256,
  851.                          rs,EL[Index]->xpos, EL[Index]->ypos,
  852.                          EL[Index]->width, EL[Index]->height, NULL);   
  853.         
  854.     }
  855.         
  856.     /* Swap the bitmaps */
  857.     Retina_SwapBitMap(rs);
  858.  
  859.     /* Erase the old images on the new background bitmap. */
  860.     for (Index=0; Index<EyeList->NumEyes; Index++) {
  861.         Retina_RectFill(rs,EL[Index]->old_xpos,
  862.                         EL[Index]->old_ypos,
  863.                         EL[Index]->old_xpos+EL[Index]->width,
  864.                         EL[Index]->old_ypos+EL[Index]->height);
  865.     }
  866. }
  867.  
  868. /*
  869.  * This is the Client Process's Main Loop
  870.  */
  871.  
  872. void __interrupt __saveds
  873. REyesClientProcess(void)
  874. {
  875.     struct ClientMessage *ClientMessage;
  876.     struct MsgPort *ClientPort;
  877.     struct Task *BlankerServerTask;
  878.     ULONG BlankerServerSigMask;
  879.     struct RetinaScreen *EyesScreen;
  880.     LONG NumEyes, Speed, Chance;
  881.     EyeStruct *EyeList;
  882.  
  883.     /* wait for Server's initial Message */
  884.  
  885.     ClientPort = FINDPROCPORT;
  886.     (void)WaitPort(ClientPort);
  887.     ClientMessage = (struct ClientMessage *)GetMsg(ClientPort);
  888.  
  889.     BlankerServerTask = ClientMessage->bcm_Message.mn_ReplyPort->mp_SigTask;
  890.     BlankerServerSigMask = ClientMessage->bcm_SigMask;
  891.  
  892.     NumEyes = ClientMessage->bcm_Eyes;
  893.     Speed = ClientMessage->bcm_Speed;
  894.     Chance = ClientMessage->bcm_Chance;
  895.     EyesScreen = ClientMessage->bcm_Screen;
  896.  
  897.     if (EyesScreen) {
  898.         if ((EyeList = CreateEyes(EyesScreen, NumEyes, Speed))== NULL) {
  899.             ClientMessage->bcm_Status = FALSE;
  900.             Forbid();
  901.             ReplyMsg((struct Message *)ClientMessage);
  902.             return;
  903.         }
  904.     }
  905.             
  906.     ClientMessage->bcm_Status = TRUE;
  907.     ReplyMsg((struct Message *)ClientMessage);
  908.  
  909.     /* Animate the blanker screen until a termination message is received. */
  910.     while ((ClientMessage = (struct ClientMessage *)GetMsg(ClientPort)) == NULL) {
  911.         if (EyesScreen) DrawEyes(EyeList, EyesScreen, Chance);
  912.     
  913.         /* 
  914.          * We signal the server after each loop so it will know that we're alive.
  915.          */
  916.         Signal(BlankerServerTask, BlankerServerSigMask);
  917.     }
  918.  
  919.     /* We are requested to finish, so we do. */
  920.  
  921.     if (EyeList) DeleteEyes(EyeList);
  922.     Forbid();
  923.     ReplyMsg((struct Message *)ClientMessage);
  924. }
  925.  
  926. /*
  927.  * The Main Loop
  928.  */
  929.  
  930. void
  931. main(LONG argc, UBYTE * argv[])
  932. {
  933.     char **ToolTypes;
  934.     CxObj *Broker, *ObjectList, *Filter;
  935.     struct IntuiMessage *IntMsg;
  936.     CxMsg *BlankerCxMsg;
  937.     LONG ThisTimeOut, TimeUntilBlank, TimeUntilBlack;
  938.     struct RetinaScreen *BlankerScreen = NULL;
  939.     struct ClientPort *ClientPort = NULL;
  940.  
  941.     /* open our Libraries */
  942.     AddTool(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",
  943.                                               37L), CloseLibrary, 0L,
  944.             "Couldn't open the intuition.library.");
  945.     AddTool(IconBase = OpenLibrary("icon.library", 37L), CloseLibrary, 0L,
  946.             "Couldn't open the icon library.");
  947.     AddTool(CxBase = OpenLibrary("commodities.library", 37L), CloseLibrary, 0L,
  948.             "Couldn't open the commoidities library.");
  949.     AddTool(GadToolsBase = OpenLibrary("gadtools.library", 37L), CloseLibrary, 0L,
  950.             "Couldn't open the gadtools library.");
  951.     AddTool(RetinaBase = (struct _xy_RetinaBase *)OpenLibrary("retina.library", 7L), 
  952.             CloseLibrary, 0L,"Couldn't open the Retina library.");
  953.  
  954.     /* get our Arguments */
  955.  
  956.     if (ToolTypes = ArgArrayInit(argc, argv))
  957.         AddTool(ToolTypes, ArgArrayDone, 0L,NULL);
  958.  
  959.     /* get some Signals */
  960.  
  961.     BlankerServerProcess = SysBase->ThisTask;
  962.     if ((bsp_TimerSig = AllocSignal(-1L)) == -1)
  963.         Quit(10,"Could not allocate a signal.");
  964.     AddTool((void *)bsp_TimerSig, FreeSignal, 0L,NULL);
  965.     if ((bsp_InputSig = AllocSignal(-1L)) == -1)
  966.         Quit(10,"Could not allocate a signal.");
  967.     AddTool((void *)bsp_InputSig, FreeSignal, 0L,NULL);
  968.     if ((bsp_ClientSig = AllocSignal(-1L)) == -1)
  969.         Quit(10,"Could not allocate a signal.");
  970.     AddTool((void *)bsp_ClientSig, FreeSignal, 0L,NULL);
  971.  
  972.     /* initialize our Broker = install us as a Commodity */
  973.  
  974.     AddTool(CxPort = CreateMsgPort(), DeleteMsgPortSafely, 0L, 
  975.             "Failed to create a port.");
  976.  
  977.     NewBroker.nb_Pri = ArgInt(ToolTypes, "CX_PRIORITY", DEF_CX_PRI);
  978.     NewBroker.nb_Port = CxPort;
  979.     AddTool(Broker = CxBroker(&NewBroker, NULL), DeleteCxObjAll, 0L, 
  980.             NULL);
  981.  
  982.     /* get Time Out, Client Time Out and Display mode */
  983.  
  984.     TimeOut = ArgIntMax(ToolTypes, "TIMEOUT", DEF_TIMEOUT, MAX_TIMEOUT);
  985.     ClientTimeOut = ArgIntMax(ToolTypes, "CLIENTTIMEOUT", DEF_CLIENT_TIMEOUT, 
  986.                                 MAX_CLIENT_TIMEOUT);
  987.  
  988.     /* get Parameters for Eye Movement */
  989.  
  990.     NumEyes = ArgIntMax(ToolTypes, "EYES", DEF_EYES, MAX_EYES);
  991.     Speed = ArgIntMax(ToolTypes, "SPEED", DEF_SPEED, MAX_SPEED);
  992.     Chance = ArgIntMax(ToolTypes, "%ANIM", DEF_CHANCE, MAX_CHANCE);
  993.  
  994.     /* install our hot keys */
  995.  
  996.     PopKey = ArgString(ToolTypes, "CX_POPKEY", DEF_POPKEY);
  997.     BlankKey = ArgString(ToolTypes, "BLANKKEY", DEF_BLANKKEY);
  998.  
  999.     if ((Filter = HotKey(PopKey, CxPort, HOTKEY_OPEN_WINDOW)) == NULL)
  1000.         Quit(10,"The CX_POPKEY tool type is invalid.");
  1001.     else
  1002.         AttachCxObj(Broker, Filter);
  1003.     if (CxObjError(Filter))
  1004.         Quit(10,"Could not link to the commodity list.");
  1005.  
  1006.     if ((Filter = HotKey(BlankKey, CxPort, HOTKEY_BLANK_SCREEN)) == NULL)
  1007.         Quit(10,"The BLANKKEY tool type is invalid.");
  1008.     else
  1009.         AttachCxObj(Broker, Filter);
  1010.     if (CxObjError(Filter))
  1011.         Quit(10,"Could not link to the commodity list.");
  1012.  
  1013.     /* install our "InputHandler" */
  1014.  
  1015.     ObjectList = CxCustom(BlankerAction, 0L);
  1016.     AttachCxObj(Broker, ObjectList);
  1017.     if (CxObjError(ObjectList))
  1018.         Quit(10,"Could not link to the commodity list.");
  1019.  
  1020.     (void)ActivateCxObj(Broker, TRUE);
  1021.     AddTool(Broker, ActivateCxObj, 0L,"The broker broke.");
  1022.  
  1023.     /* open Window on startup if not forbidden */
  1024.  
  1025.     if (stricmp(ArgString(ToolTypes, "CX_POPUP", ""), "NO"))
  1026.         OpenBlankerWindow();
  1027.  
  1028.     /* increase our Priority */
  1029.  
  1030.     AddTool(FindTask(NULL), SetTaskPri, (LONG) SetTaskPri(FindTask(NULL), SERVER_PRI),
  1031.             "Findtask failed!");
  1032.  
  1033.     /* start the Loop */
  1034.  
  1035.     TimeUntilBlank = ThisTimeOut = 10L * TimeOut;
  1036.     TimeUntilBlack = 10L * ClientTimeOut;
  1037.  
  1038.     FOREVER
  1039.     {
  1040.         ULONG Mask;
  1041.  
  1042.         if (BlankerWindow)
  1043.             Mask = Wait(MASK(bsp_TimerSig) | MASK(bsp_InputSig) | MASK(bsp_ClientSig) |
  1044.                         MASK(CxPort->mp_SigBit) | 
  1045.                         MASK(BlankerWindow->UserPort->mp_SigBit) |
  1046.                         SIGBREAKF_CTRL_C);
  1047.         else
  1048.             Mask = Wait(MASK(bsp_TimerSig) | MASK(bsp_InputSig) | MASK(bsp_ClientSig) |
  1049.                         MASK(CxPort->mp_SigBit) | SIGBREAKF_CTRL_C);
  1050.  
  1051.         /* process Window Events */
  1052.  
  1053.         while ((BlankerWindow != NULL) && (IntMsg = 
  1054.             GT_GetIMsg(BlankerWindow->UserPort)))
  1055.             switch (IntMsg->Class) {
  1056.                     struct Gadget *Clicked;
  1057.                     UWORD Code;
  1058.  
  1059.                 case IDCMP_CLOSEWINDOW:
  1060.                     GT_ReplyIMsg(IntMsg);
  1061.                     CloseBlankerWindow();
  1062.                     break;
  1063.                 case IDCMP_REFRESHWINDOW:
  1064.                     GT_BeginRefresh(BlankerWindow);
  1065.                     GT_EndRefresh(BlankerWindow, TRUE);
  1066.                     break;
  1067.                 case IDCMP_GADGETUP:
  1068.                     Code = IntMsg->Code;
  1069.                     Clicked = (struct Gadget *)IntMsg->IAddress;
  1070.                     GT_ReplyIMsg(IntMsg);
  1071.                     switch (Clicked->GadgetID) {
  1072.                         case GID_HIDE:
  1073.                             CloseBlankerWindow();
  1074.                             break;
  1075.                         case GID_QUIT:
  1076.                             Quit(0,"Normal Termination.");
  1077.                         case GID_BLANK:
  1078.                             if (TimeUntilBlank)
  1079.                                 TimeUntilBlank = ThisTimeOut = 2L;
  1080.                             break;
  1081.                         case GID_TIMEOUT:
  1082.                             if (GetNum(Clicked, &TimeOut, MAX_TIMEOUT))
  1083.                                 TimeUntilBlank = ThisTimeOut = 10L * TimeOut;
  1084.                             break;
  1085.                         case GID_CLIENT:
  1086.                             if (GetNum(Clicked, &ClientTimeOut, MAX_CLIENT_TIMEOUT))
  1087.                                 TimeUntilBlack = 10L * ClientTimeOut;
  1088.                             break;
  1089.                         case GID_EYES:
  1090.                             NumEyes = Code;
  1091.                             break;
  1092.                         case GID_SPEED:
  1093.                             Speed = Code;
  1094.                             break;
  1095.                         case GID_CHANCE:
  1096.                             Chance = Code;
  1097.                             break;
  1098.                     }
  1099.                     break;
  1100.                 case IDCMP_VANILLAKEY:
  1101.                     Code = IntMsg->Code;
  1102.                     GT_ReplyIMsg(IntMsg);
  1103.                     switch ((char)Code) {
  1104.                         case 'H':
  1105.                         case 'h':
  1106.                             CloseBlankerWindow();
  1107.                             break;
  1108.                         case 'Q':
  1109.                         case 'q':
  1110.                             Quit(0,"Normal Termination.");
  1111.                         case 'B':
  1112.                         case 'b':
  1113.                             if (TimeUntilBlank)
  1114.                                 TimeUntilBlank = ThisTimeOut = 2L;
  1115.                     }
  1116.                     break;
  1117.                 default:
  1118.                     GT_ReplyIMsg(IntMsg);
  1119.             }
  1120.  
  1121.         /* process Commodity Messages */
  1122.  
  1123.         while (BlankerCxMsg = (CxMsg *) GetMsg(CxPort))
  1124.             HandleCxMsg(Broker, BlankerCxMsg, &TimeUntilBlank, &ThisTimeOut);
  1125.  
  1126.         /* check for <CTRL>-C */
  1127.  
  1128.         if (Mask & SIGBREAKF_CTRL_C)
  1129.             Quit(0,"Normal Termination.");
  1130.  
  1131.         /* Input detected, unblank if necessary */
  1132.  
  1133.         if (Mask & MASK(bsp_InputSig)) {
  1134.             if (TimeUntilBlank == 0L) {
  1135.                 if (ClientPort)
  1136.                     RemTool(ClientPort);
  1137.                 
  1138.                 if (BlankerScreen) {
  1139.                     SpritesOn(BlankerScreen);
  1140.                     RemTool(BlankerScreen);
  1141.                 } else
  1142.                     Retina_DisplayOn();
  1143.                     
  1144.                 ThisTimeOut = 10L * TimeOut;
  1145.             }
  1146.             TimeUntilBlank = ThisTimeOut;
  1147.         }
  1148.  
  1149.         /* client has confirmed that it is still alive */
  1150.         if (Mask & MASK(bsp_ClientSig)) {
  1151.             if (BlankerScreen) Retina_DisplayOn();
  1152.             TimeUntilBlack = 10L * ClientTimeOut;
  1153.         }
  1154.         /* 1/10 sec is over */
  1155.  
  1156.         if (Mask & MASK(bsp_TimerSig))
  1157.             if (TimeUntilBlank) {
  1158.                 TimeUntilBlank--;
  1159.                 if (TimeUntilBlank == 0L) {    /* Time Out reached, blank
  1160.                                              * the screen */
  1161.                     struct ClientMessage ClientMessage;
  1162.  
  1163.                     BlankerScreen=CreateScreen();
  1164.                     if (BlankerScreen) 
  1165.                         AddTool(BlankerScreen, DestroyScreen, 0L,NULL);
  1166.                     else
  1167.                         /* do this if we're completely out of video memory. */
  1168.                         Retina_DisplayOff();  
  1169.  
  1170.                     ClientMessage.bcm_Screen = BlankerScreen;
  1171.                     ClientMessage.bcm_SigMask = 1L << bsp_ClientSig;
  1172.                     ClientMessage.bcm_Eyes = NumEyes;
  1173.                     ClientMessage.bcm_Speed = Speed;
  1174.                     ClientMessage.bcm_Chance = Chance;
  1175.  
  1176.                     if (ClientPort = CreateBlankerClient(REyesClientProcess, 
  1177.                         &ClientMessage)) {
  1178.                         TimeUntilBlack = 10L * ClientTimeOut;    
  1179.                         /* try to start Client */
  1180.                         AddTool(ClientPort, DeleteBlankerClient, 0L,NULL);
  1181.                     }
  1182.                 }
  1183.             } else {
  1184.                 if ((BlankerScreen)&&(RetinaBase->rb_FirstScreen != BlankerScreen)) {
  1185.                     Retina_ScreenToFront(BlankerScreen);
  1186.                     SpritesOff(BlankerScreen);
  1187.                 }
  1188.                 if (TimeUntilBlack) {
  1189.                     TimeUntilBlack--;
  1190.                     if (TimeUntilBlack == 0L)
  1191.                         Retina_DisplayOff();    /* Client Time Out
  1192.                                                  * reached, turn entire
  1193.                                                  * screen black */
  1194.                 }
  1195.             }
  1196.     }
  1197. }
  1198.